#!/system/bin/sh

scripts_dir="${0%/*}"
source /data/adb/box/settings.ini

PROPFILE="/data/adb/modules/box_for_root/module.prop"

box_check_logs() {
  # Delete logs for each bin in the list
  log Info "deleting and backup logs"
  for bin in "${bin_list[@]}"; do
    if [ -f "${box_run}/${bin}.log" ]; then
      mv "${box_run}/${bin}.log" "${box_run}/${bin}.old.log"
    fi
  done
  # Delete other log files
  find "${box_run}" -maxdepth 1 -type f \( -name "root" -o -name "*.list" -o -name "*.inotify.log" \) -exec rm -f {} +
  # Delete logs that are three days old or older
  find "${box_run}" -maxdepth 1 -type f -name "*.log" -mtime +3 -exec rm -f {} +
}

box_bin_alive() {
  local PID=$(<"${box_pid}" 2>/dev/null)
  if ! kill -0 "$PID" 2>/dev/null; then
    log Error "$(<"${box_run}/${bin_name}.log")"
    log Error "${bin_name} service is not running."
    log Error "please check ${bin_name}.log for more information."
    log Error "killing stale pid $PID"
    for bin in "${bin_list[@]}"; do
      killall -15 "${bin}" >/dev/null 2>&1 || busybox pkill -15 "${bin}" >/dev/null 2>&1 
    done
    "${scripts_dir}/box.iptables" disable >/dev/null 2>&1
    [ -f "${box_pid}" ] && rm -f "${box_pid}"
    exit 1
  else
    return 0
  fi
}

box_run_crontab() {
  # start crond with the "-c" option and keep it in the background
  nohup busybox crond -c "${box_run}" > /dev/null 2>&1 &
  # delete the previous crontab and create a new crontab
  busybox crontab -c "${box_run}" -r
  touch "${box_run}/root"
  chmod 0755 "${box_run}/root"

  if [ "${run_crontab}" = "true" ]; then
    log Debug "Cron job enabled"
    echo "${interva_update} ${scripts_dir}/box.tool geosub" >> "${box_run}/root"
    log Debug "Interval crontab geox and subs: ${interva_update}."
    log Info "${bin_name} geox updates: ${update_geo}."
    if [ "${bin_name}" = "clash" ]; then
      log Info "${bin_name} subscription update: ${update_subscription}."
    fi
  else
    log Info "Cron Job disabled"
    log Info "Crontab geox and subscription is disabled."
  fi
}

xclash() {
  local xclash_option="${xclash_option:-mihomo}"
  # default to "mihomo" if xclash_option is not set
  current_clash="$(readlink "${bin_dir}/clash")"

  if [ "$current_clash" != "${bin_dir}/xclash/${xclash_option}" ]; then
    if [ -f "${bin_dir}/xclash/${xclash_option}" ]; then
      if ! ln -sf "${bin_dir}/xclash/${xclash_option}" "${bin_dir}/clash"; then
        log Error "Failed to use ${xclash_option}"
        return 1
      fi
    else
      mkdir -p "${bin_dir}/xclash"
      log Error "${bin_dir}/xclash/${xclash_option} file not found"
      return 1
    fi
  fi
  log Info "xclash [ $xclash_option ] setup completed"
}

box_ownership() {
  # Set ownership and permission of kernel directory
  chown -R ${box_user_group} ${box_dir}
  chmod -R 644 ${box_dir}/${bin_name}

  chown ${box_user_group} ${bin_path}
  chmod 6755 ${bin_path}

  chmod 0700 ${box_dir}/bin/yq
  chmod 0700 ${box_dir}/bin/curl
}

box_permission() {
  if [[ "${box_user_group}" == @(root:net_admin|0:3005) && -f "${bin_path}" ]]; then
    # Set ownership and permission of kernel directory
    box_ownership
    log Info "Using kernel in ${bin_path}."
  else
    if  [[ "${box_user_group}" != @(root:net_admin|0:3005) ]]; then
      log Error "does't support user_group [ $box_user_group ]"
      sed -i "s/box_user_group=.*/box_user_group=\"root:net_admin\"/g" ${settings}
      log Debug "automatically changed to [ root:net_admin ], restart box"
      exit 1
    fi
    log Error "Kernel [ ${bin_name} ] is missing."
    log Error "Please download the [ ${bin_name} ] kernel and place it in the ${bin_dir}/ directory."
    log Debug "exec 'su -c /data/adb/box/scripts/box.tool upkernel' in terminal"
    exit 1
  fi
}

box_check_bin() {
  if [ ! -x "${bin_path}" ]; then
    log Error "${bin_path} is not executable."
    exit 1
  fi
  case "${bin_name}" in
    clash) version_output=$("${bin_path}" -v) >/dev/null 2>&1 || return 1;;
    *) version_output=$("${bin_path}" version) >/dev/null 2>&1 || return 1;;
  esac
  log Info "${version_output}"
}

box_create_tun() {
  mkdir -p /dev/net
  [ ! -L /dev/net/tun ] && ln -s /dev/tun /dev/net/tun

  if [ ! -c "/dev/net/tun" ]; then
      log Error "Cannot create /dev/net/tun. Possible reasons:"
      log Warning "Your system does not support the TUN/TAP driver."
      log Warning "Your system kernel version is not compatible with the TUN/TAP driver."
      sed -i 's/network_mode=.*/network_mode="tproxy"/g' "${settings}"
      exit 1
  fi
}

prepare_singbox() {
  # Check configuration file
  if ! [ -f "${sing_config}" ]; then
    log Error "Configuration file ${sing_config} not found"
    exit 1
  else
    log Info "Config ${sing_config} found"
  fi

  # Check yq
  yq="yq"
  if ! command -v yq &>/dev/null; then
    if [ ! -e "${box_dir}/bin/yq" ]; then
      log Debug "yq file not found, starting download from GitHub"
      ${scripts_dir}/box.tool upyq
    fi
    yq="${box_dir}/bin/yq"
  fi

  # Set auto_detect_interface/auto_route
  ${yq} '.route.auto_detect_interface = true' -i --output-format=json "${sing_config}"
  ${yq} '(.inbounds[] | select(.type == "tun") | .auto_route) |= true' -i --output-format=json "${sing_config}"

  # Format sing-box configuration
  if ${bin_path} format -w -D "${box_dir}/${bin_name}" -C "${box_dir}/${bin_name}" > "${box_run}/${bin_name}.log" 2>&1; then
    # Set auto_route based on network_mode
    if [[ "${network_mode}" == @(mixed|tun) ]]; then
      # Check if "type" is "tun" in configuration
      if ! busybox grep -q '"type": "tun"' "${sing_config}"; then
        # Add "tun" configuration if missing
        ${yq} '.inbounds += [{
          "type": "tun",
          "tag": "tun-in",
          "interface_name": "utun9",
          "address": ["172.18.0.1/30","fdfe:dcba:9876::1/126"],
          "mtu": 9000,
          "stack": "system",
          "auto_route": true,
          "strict_route": true,
          "auto_redirect": true,
          "sniff": true,
          "sniff_override_destination": false,
          "include_android_user": [0,10],
          "include_package": [],
          "exclude_package": []
        }]' -i --output-format=json "${sing_config}"
        log Debug "[Tun] configuration added to ${sing_config}"
      fi
    else
      # Set auto_route to false for non-"tun" network_mode
      sed -i 's/auto_route": true/auto_route": false/g' "${box_dir}/sing-box/"*.json
      # Set auto_detect_interface to false
      sed -i 's/"auto_detect_interface": true/"auto_detect_interface": false/g' "${box_dir}/sing-box/"*.json

      # Check if "type" is "tproxy" in configuration
      if ! busybox grep -q '"type": "tproxy"' "${sing_config}"; then
        # Add "tproxy" configuration if missing
        ${yq} '.inbounds += [{
          "type": "tproxy",
          "tag": "tproxy-in",
          "listen": "::",
          "listen_port": '"${tproxy_port}"',
          "sniff": true,
          "sniff_override_destination": false
        }]' -i --output-format=json "${sing_config}"
        log Debug "[Tproxy] configuration added to ${sing_config}"
      fi

      # del tun
      ${yq} 'del(.inbounds[] | select(.type == "tun"))' -i --output-format=json "${sing_config}"

      # Sync tproxy port in sing-box configuration
      for file in "${box_dir}/sing-box/"*.json; do
        if busybox grep -q '"type": "tproxy"' "${file}"; then
          ${yq} '(.inbounds[] | select(.type == "tproxy") | .listen_port) = '"${tproxy_port}" -i --output-format=json "${file}"
        fi
      done
    fi

    # add exclude_package/include_package for tun
    # "${yq}" '(.inbounds[] | select(.type == "tun") | .include_package) = []' -i --output-format=json "${sing_config}"
    # "${yq}" '(.inbounds[] | select(.type == "tun") | .exclude_package) = []' -i --output-format=json "${sing_config}"
    # [ ${proxy_mode} = "blacklist" ] && local mode="exclude" || mode="include"
    # for package in "${packages_list[@]}"; do
      # "${yq}" eval '(.inbounds[] | select(.type == "tun") | .'${mode}'_package) += ["'${package}'"]' -i --output-format=json "${sing_config}"
    # done

    # Add "redirect" configuration based on network_mode
    if [[ "${network_mode}" == @(mixed|enhance|redirect) ]]; then
      if ! busybox grep -q '"type": "redirect"' "${sing_config}"; then
        # Add "redirect" configuration if missing
        ${yq} '.inbounds += [{
          "type": "redirect",
          "tag": "redirect-in",
          "listen": "::",
          "listen_port": '"${redir_port}"',
          "sniff": true,
          "sniff_override_destination": false
        }]' -i --output-format=json "${sing_config}"
        log Debug "[Redirect] configuration added to ${sing_config}"
      fi

      # Sync redir_port port in sing-box configuration
      for file in "${box_dir}/sing-box/"*.json; do
        if busybox grep -q '"type": "redirect"' "${file}"; then
          ${yq} '(.inbounds[] | select(.type == "redirect") | .listen_port) = '"${redir_port}" -i --output-format=json "${file}"
        fi
      done
    fi
  else
    log Error "$(<"${box_run}/${bin_name}.log")"
    log Error "Configuration failed. Please check the ${box_run}/${bin_name}.log file."
    exit 1
  fi
}

prepare_clash() {
  # check configuration file
  if ! [ -f "${clash_config}" ]; then
    log Error "configuration file ${clash_config} not found"
    exit 1
  else
    log Info "config ${clash_config}"
  fi

  # ipv6=$(busybox awk '/ipv6:/ { print $2; found=1; exit } END{ if(!found) print "false" }' "${clash_config}" | head -n 1 2>/dev/null)
  # sed -i "s/ipv6=.*/ipv6=\"${ipv6}\"/g" ${settings}
  # sed -i "s/ipv6:.*/ipv6: ${ipv6}/g" "${clash_config}"

  # write external_controller, if not in $clash_config
  clash_external_controller=$(busybox awk '!/^ *#/ && /external-controller: /{print $1}' "${clash_config}")
  if [ -z "${clash_external_controller}" ]; then
    printf "\nexternal-controller: 0.0.0.0:9090" >> "${clash_config}"
  fi

  # write external_ui, if not in $clash_config
  clash_external_ui=$(busybox awk '!/^ *#/ && /external-ui: /{print $1}' "${clash_config}")
  if [ -z "${clash_external_ui}" ]; then
    printf "\nexternal-ui: ./dashboard" >> "${clash_config}"
  fi

  # write tproxy-port, if not in $clash_config
  clash_tproxy_port=$(busybox awk '!/^ *#/ && /tproxy-port: /{print $1}' "${clash_config}")
  if [ -z "${clash_tproxy_port}" ]; then
    printf "\ntproxy-port: ${tproxy_port}" >> "${clash_config}"
  fi

  # write redir-port, if not in $clash_config
  clash_redir_port=$(busybox awk '!/^ *#/ && /redir-port: /{print $1}' "${clash_config}")
  if [ -z "${clash_redir_port}" ]; then
    printf "\nredir-port: ${redir_port}" >> "${clash_config}"
  fi

  if [[ "${network_mode}" == @(mixed|tun) ]]; then
    clash_tun_status=$(busybox awk '!/^ *#/ && /tun:/ { getline; split($0, arr, ": "); print arr[2]; found=1; exit } END{ if (!found) print "" }' "${clash_config}" 2>/dev/null)
    # write TUN settings, if not in $clash_config
    if [ -z "${clash_tun_status}" ]; then
      printf '%s\n' '' 'tun:' \
        '  enable: true' \
        '  mtu: 9000' \
        '  device: utun' \
        '  stack: system # mixed / gvisor / system / lwip' \
        '  dns-hijack:' \
        '    - any:53' \
        '    - tcp://any:53' \
        '  auto-route: true' \
        '  strict-route: false' \
        '  auto-detect-interface: true' \
        '  include-android-user: [0, 10]' \
        '  exclude-package: []' \
        '  include-package: []' \ >> "${clash_config}"
      log Debug "[tun] configuration has been added to ${clash_config}"
    else
      log Info  "type [tun] already exists in ${clash_config}"
    fi

    # add exclude-package/include-package for tun
    # package=$(IFS=","; echo "${packages_list[*]}" | tr ' ' ',')
    # list_package="${package:-\"\"}"
    # if [ "${proxy_mode}" = "whitelist" ]; then
      # mode="include-package"
    # elif [ "${proxy_mode}" = "blacklist" ]; then
      # mode="exclude-package"
    # fi
    # sed -i "s/exclude-package:.*/exclude-package: []/g" "${clash_config}"
    # sed -i "s/include-package:.*/include-package: []/g" "${clash_config}"
    # sed -i "s/${mode}:.*/${mode}: [\"${list_package//,/\",\"}\"]/g" "${clash_config}"

    sed -i "/tun:/ {n;s/enable: false/enable: true/}" "${clash_config}"
  else
    sed -i "/tun:/ {n;s/enable: true/enable: false/}" "${clash_config}"
  fi

  # sync tproxy/redir port
  sed -i -E "s/(tproxy-port: )[0-9]+/\1${tproxy_port}/" "${clash_config}"
  sed -i -E "s/(redir-port: )[0-9]+/\1${redir_port}/" "${clash_config}"

  clash_enhanced_mode=$(busybox awk '!/^ *#/ && /enhanced-mode: / { print $2 }' "${clash_config}" 2>/dev/null)
  if [ -z "${clash_enhanced_mode}" ]; then
    # Add enhanced-mode: fake-ip
    sed -i '/dns:/ {n; /enable:.*/ {a\  enhanced-mode: fake-ip}}' "$clash_config"
    log Debug "enhanced-mode: fake-ip add success"
  fi

  if [[ "${network_mode}" == @(mixed|tproxy|redirect|enhance) ]]; then
    if [[ -n "${packages_list[*]}" || -n "${gid_list[*]}" ]] && [ "${clash_enhanced_mode}" = "fake-ip" ]; then
      log Warning "${proxy_mode} only works in enhanced-mode: redir-host xclash[mihomo]"
      log Warning "auto replace fake-ip to redir-host"
      sed -i "s/enhanced-mode:.*/enhanced-mode: redir-host/g" "${clash_config}"
    fi
  fi
}

box_run_bin() {
  log Info "client-list: [ ${bin_list[*]} ]"
  log Info "choose: ${bin_name}, start the service."
  ulimit -SHn 1000000
  # Use ulimit to limit the memory usage of a process to 200MB
  # ulimit -v 200000  # Set the virtual memory limit in KB
  case "${bin_name}" in
    hysteria)
      # sync port
      sed -i -e "/tcpTProxy:/,/listen:/s/listen: :.*/listen: :${tproxy_port}/" "${box_dir}/${bin_name}/config.yaml"
      sed -i -e "/udpTProxy:/,/listen:/s/listen: :.*/listen: :${tproxy_port}/" "${box_dir}/${bin_name}/config.yaml"

      # set network_mode variable value to "tproxy"
      if [[ "${network_mode}" != "tproxy" ]]; then
        sed -i 's/\(network_mode=\)\"[^\"]*\"/\1"tproxy"/g' ${settings}
      fi
      nohup busybox setuidgid ${box_user_group} ${bin_path} -c ${box_dir}/${bin_name}/config.yaml > "${bin_log}" 2>&1 &
      PID=$!
      echo -n $PID > "${box_pid}"
      sleep 1
      ;;
    sing-box)
      prepare_singbox
      if ${bin_path} check -D "${box_dir}/${bin_name}" -C "${box_dir}/${bin_name}" > "${box_run}/${bin_name}.log" 2>&1; then
        nohup busybox setuidgid "${box_user_group}" "${bin_path}" run -D "${box_dir}/${bin_name}" -C "${box_dir}/${bin_name}" > "${bin_log}" 2>&1 &
        PID=$!
        echo -n $PID > "${box_pid}"
        sleep 1
      else
        log Error "$(<"${box_run}/${bin_name}.log")"
        log Error "configuration failed. Please check the ${box_run}/${bin_name}.log file."
        exit 1
      fi
      ;;
    clash)
      prepare_clash
      if ${bin_path} -t -d "${box_dir}/${bin_name}" -f "${clash_config}" > "${box_run}/${bin_name}.log" 2>&1; then
        nohup busybox setuidgid "${box_user_group}" "${bin_path}" -d "${box_dir}/${bin_name}" -f "${clash_config}" > "${bin_log}" 2>&1 &
        PID=$!
        echo -n $PID > "${box_pid}"
        sleep 1
      else
        log Error "$(<"${box_run}/${bin_name}.log")"
        log Error "configuration failed. Please check the ${box_run}/${bin_name}.log file."
        exit 1
      fi
      ;;
    xray)
      # set network_mode variable value to "tproxy"
      if [[ "${network_mode}" != "tproxy" ]]; then
        sed -i 's/\(network_mode=\)\"[^\"]*\"/\1"tproxy"/g' ${settings}
      fi

      # sync port
      # sed -i "s/port = [0-9]*\.[0-9]*/port = ${tproxy_port}.0/" ${box_dir}/$bin_name/config.toml

      # check configuration file
      if ! [ -f "${box_dir}/${bin_name}/config.toml" ] && ! [ -f "${box_dir}/${bin_name}/config.json" ]; then
        log Error "configuration file not found: ${box_dir}/${bin_name}/config.toml or config.json"
        rm -f "${box_pid}"
        exit 1
      else
        # Displays a configuration xray"
        log Info "config ${box_dir}/${bin_name}/*.json, or *.toml"
      fi

      # run xray
      export XRAY_LOCATION_ASSET="${box_dir}/${bin_name}"
      if ${bin_path} -test -confdir "${box_dir}/${bin_name}" > "${box_run}/${bin_name}.log" 2>&1; then
        nohup busybox setuidgid "${box_user_group}" "${bin_path}" run -confdir "${box_dir}/${bin_name}" > "${bin_log}" 2>&1 &
        PID=$!
        echo -n $PID > "${box_pid}"
        sleep 1
      else
        log Error "$(<"${box_run}/${bin_name}.log")"
        log Error "configuration failed. Please check the ${box_run}/${bin_name}.log file."
        exit 1
      fi
      ;;
    v2fly)
      # set network_mode variable value to "tproxy"
      if [[ "${network_mode}" != "tproxy" ]]; then
        sed -i 's/\(network_mode=\)\"[^\"]*\"/\1"tproxy"/g' ${settings}
      fi

      # sync port
      # sed -i "s/port = [0-9]*\.[0-9]*/port = ${tproxy_port}.0/" ${box_dir}/$bin_name/config.toml

      # check configuration file
      if ! [ -f "${box_dir}/${bin_name}/config.toml" ] && ! [ -f "${box_dir}/${bin_name}/config.json" ]; then
        log Error "configuration file not found: ${box_dir}/${bin_name}/config.toml or config.json"
        exit 1
      else
        # Displays a configuration v2fly"
        log Info "config ${box_dir}/${bin_name}/*.json, or *.toml"
      fi

      # run v2ray
      export V2RAY_LOCATION_ASSET="${box_dir}/${bin_name}"
      if ${bin_path} test -d "${box_dir}/${bin_name}" > "${box_run}/${bin_name}.log" 2>&1; then
        nohup busybox setuidgid "${box_user_group}" "${bin_path}" run -d "${box_dir}/${bin_name}" > "${bin_log}" 2>&1 &
        PID=$!
        echo -n $PID > "${box_pid}"
        sleep 1
      else
        log Error "$(<"${box_run}/${bin_name}.log")"
        log Error "configuration failed. Please check the ${box_run}/${bin_name}.log file."
        exit 1
      fi
      ;;
    *)
      log Error "[ ${bin_name} ] unknown binary."
      exit 1
      ;;
  esac
}

box_cgroup() {
  set_cgroup_config() {
    local cgroup_attr="$1"
    local cgroup_value="$2"

    if [ "${cgroup_value}" = "true" ]; then
      if ${scripts_dir}/box.tool "${cgroup_attr}"; then
        true
      else
        log Warning "failed to enable ${cgroup_attr} for ${bin_name}."
        log Warning "cgroups ${cgroup_attr} is turned off"
        sed -i -E "/cgroup_${cgroup_attr}/ s/(true)/false/" "${settings}"
      fi
    fi
  }
  set_cgroup_config "memcg" "${cgroup_memcg}"
  set_cgroup_config "cpuset" "${cgroup_cpuset}"
  set_cgroup_config "blkio" "${cgroup_blkio}"
}

# Function to display the usage of a binary
# This script retrieves information about a running binary process and logs it to a log file.
box_bin_status() {
  # Get the process ID of the binary
  local PID=$(busybox pidof ${bin_name})

  if [ -z "$PID" ]; then
    log Error "${bin_name} is not running."
    return 1
  fi

  stack=$(if [ "${bin_name}" != "clash" ]; then find "/data/adb/box/sing-box" -type f -name "*.json" -exec busybox awk -F'"' '/"stack"/{print $4}' {} +; else busybox awk '!/^ *#/ && /stack: / { print $2;found=1; exit}' "${clash_config}"; fi)
  TOAST=1 log Info "${bin_name} service is running."

  log Info "proxy: ${proxy_mode} + network: ${network_mode} + $(if [[ "${network_mode}" == @(mixed|tun) ]]; then echo "stack: ${stack}"; fi)"

  # Get the memory usage of the binary
  rss=$(grep VmRSS /proc/$PID/status | busybox awk '{ print $2 }')
  [ "${rss}" -ge 1024 ] && bin_rss="$(expr ${rss} / 1024) MB" || bin_rss="${rss} KB"
  swap=$(grep VmSwap /proc/$PID/status | busybox awk '{ print $2 }')
  [ "${swap}" -ge 1024 ] && bin_swap="$(expr ${swap} / 1024) MB" || bin_swap="${swap} KB"

  # Get the state of the binary
  state=$(grep State /proc/$PID/status | busybox awk '{ print $2" "$3 }')

  # Get the user and group of the binary
  user_group=$(stat -c %U:%G /proc/$PID)

  # Log the information
  log Info "${bin_name} has started with the '${user_group}' user group."
  log Info "${bin_name} status: ${state} (PID: $PID)"
  log Info "${bin_name} memory usage: ${bin_rss}, swap: ${bin_swap}"

  # Get the CPU usage of the binary
  cpu=$(ps -p $PID -o %cpu | busybox awk 'NR==2{print $1}' 2> /dev/null)

  cpus_allowed=$(grep Cpus_allowed_list /proc/$PID/status | busybox awk '{ print $2" "$3 }')
  cpuset=$(ps -p $PID -o cpu | busybox awk 'NR==2{print $1}' 2> /dev/null)

  if [ -n "${cpu}" ]; then
    log Info "${bin_name} CPU usage: ${cpu}%"
  else
    log Info "${bin_name} CPU usage: not available"
  fi
  if [ -n "${cpuset}" ]; then
    log Info "${bin_name} list of allowed CPUs : ${cpus_allowed}"
    log Info "${bin_name} Which CPU running on : ${cpuset}"
  else
    log Info "${bin_name} Which CPU running on : not available"
  fi

  # Check battery temperature
  temperature_celsius=$(($(cat /sys/class/power_supply/battery/temp) / 10))
  log Info "battery temperature: ${temperature_celsius}°C"

  # Get the running time of the binary
  running_time=$(busybox ps -o comm,etime | grep ${bin_name} | busybox awk '{print $2}')
  if [ -n "${running_time}" ]; then
    log Info "${bin_name} running time: ${running_time}"
  else
    log Info "${bin_name} running time: not available."
  fi

  # Save the process ID to the pid file
  if [ -n "$PID" ]; then
    sed -Ei "s/^description=(\[.*][[:space:]]*)?/description=[ ⏲ $current_time | ✔ $bin_name service is running!!! ] /g" "$PROPFILE"
    echo -n "$PID" > "${box_pid}"
  fi
}

start_box() {
  # Clear the log file and add the timestamp and delimiter
  # cd /data/adb/box/bin; chmod 755 *
  sed -Ei "s/^description=(\[.*][[:space:]]*)?/description=[ ⏲ $current_time | ☹ Module is working! but no service is running ] /g" "$PROPFILE"

  echo -n "" > "${box_log}"
  box_version=$(busybox awk '!/^ *#/ && /version=/ { print $0 }' "/data/adb/modules/box_for_root/module.prop" 2>/dev/null)

  if [ -t 1 ]; then
    echo -e "${yellow}$(getprop persist.sys.timezone)${normal}"
    echo -e "${yellow}$(getprop gsm.sim.operator.alpha) / $(getprop gsm.network.type)${normal}"
    echo -e "${yellow}$(date)${normal}"
    echo -e "${yellow}${box_version}${normal}"
    echo -e "${yellow}$(getprop ro.product.cpu.abi)${normal}"
    echo -e "${white}━━━━━━━━━━━━━━━━━━${normal}"
  else
    {
      echo "$(getprop persist.sys.timezone)"
      echo "$(getprop gsm.sim.operator.alpha) / $(getprop gsm.network.type)"
      echo "$(date)"
      echo "${box_version}"
      echo "$(getprop ro.product.cpu.abi)"
      echo "━━━━━━━━━━━━━━━━━━"
    } | tee -a "${box_log}" > /dev/null 2>&1
  fi

  # Update iptables if bin_name is still running
  # PIDS=("clash" "xray" "sing-box" "v2fly")
  PIDS=("${bin_list[@]}")
  PID=""
  i=0

  while [ -z "$PID" ] && [ "$i" -lt "${#PIDS[@]}" ]; do
    PID=$(busybox pidof "${PIDS[$i]}")
    i=$((i+1))
  done

  if [ -n "$PID" ]; then
    pid_name="${box_dir}/run/pid_name.txt"
    ps -p $PID -o comm= > "${pid_name}"
    sed -i '/^[[:space:]]*$/d' "${pid_name}"
    log Debug "$(<"${pid_name}")(PID: $PID) service is still running, auto restart BOX."
    rm -f "${pid_name}"
    stop_box
    start_box && "${scripts_dir}/box.iptables" renew
    exit 1
  fi

  # Checks if bin_name is defined
  case "${bin_name}" in
    clash|xray|sing-box|v2fly|hysteria)
      log Info "Good day"
      [ "${bin_name}" = "clash" ] && {
        xclash || exit 1
      }
      ;;
    *)
      log Error "bin_name: [ ${bin_name} ] unknown not defined."
      exit 1
      ;;
  esac

  # apk manager check
  versionName=$(dumpsys package xyz.chz.bfm | grep versionName | busybox awk -F '=' '{print $2}' | sed 's/-.*//')
  if [[ -n "${versionName}" && $(echo "${versionName}" | busybox awk '{print ($1 < 1.13)}') -eq 1 ]]; then
    log Error "Update BFR Manager Apps, Use version 1.13.+"
    log Error "current version: ${versionName}"
    exit 1
  else
    [ -n "${versionName}" ] && log Info "BFR Manager: ${versionName}"
  fi
  
  # busybox check
  busybox_code=$(busybox | head -n 1 | busybox awk '{print $2}' | busybox grep -oE '[0-9.]*')
  # busybox_code=$(busybox | head -n 1 | busybox awk '{print $2}' | grep -oE [0-9.]*")
  if [ "$(echo "${busybox_code}" | busybox awk -F. '{printf "%03d%03d%03d\n", $1, $2, $3}')" -lt "$(echo "1.36.1" | busybox awk -F. '{printf "%03d%03d%03d\n", $1, $2, $3}')" ]; then
    log Info "Current $(which busybox) v${busybox_code}"
    log Warning "Please update your busybox to v1.36.1+"
  else
    log Info "Current $(which busybox) v${busybox_code}"
  fi

  # Check permissions, check for bin existence, delete old logs, create a TUN if necessary, run box, and wait for 1 second
  box_permission
  if ! box_check_bin; then
    log Error "${bin_name} version information not available."
    exit 1
  fi
  box_check_logs

  # Execute the box_create_tun functions
  if [[ "${network_mode}" == @(mixed|tun) ]]; then
    box_create_tun
  fi

  # Execute box_run_crontab if run_crontab is not equal to "false"
  [ "${run_crontab}" = "true" ] && box_run_crontab || log Info "crontab disabled."

  # Execute the box_cgroup, box_run_bin, box_detected_port, box_bin_alive,box_bin_status functions
  box_run_bin
  box_cgroup

  count=0
  while [ $count -le 10 ]; do
    sleep 0.17
    box_bin_alive || break
    count=$((count + 1))
  done
  box_bin_status
  true
}

stop_box() {
  stop_cron
  # Kill each binary using a loop
  for bin in "${bin_list[@]}"; do
    # Check if the binary is running using pgrep
    if busybox pgrep "${bin}" >/dev/null; then
      # Use `busybox pkill` to kill the binary with signal 15, otherwise use `killall`.
      if busybox pkill -15 "${bin}" >/dev/null 2>&1; then
        : # Do nothing if busybox pkill is successful
      else
        killall -15 "${bin}" >/dev/null 2>&1 || kill -15 "$(busybox pidof "${bin}")" >/dev/null 2>&1
      fi
    fi
  done
  # Check if the binary has stopped
  sleep 0.5
  if ! busybox pidof "${bin_name}" >/dev/null 2>&1; then
    # Delete the `box.pid` file if it exists
    if [ -f "${box_pid}" ]; then
      rm -f "${box_pid}"
    fi
    log Warning "${bin_name} shutting down, service is stopped."
    TOAST=1 log Warning "${bin_name} disconnected."

    [ -t 1 ] && echo -e "${white}━━━━━━━━━━━━━━━━━━${normal}"
  else
    log Warning "${bin_name} Not stopped; may still be shutting down or failed to shut down."
    force_stop
  fi

  sed -Ei "s/^description=(\[.*][[:space:]]*)?/description=[ ⏲ $current_time | ✘ $bin_name shutting down, service is stopped !!! ] /g" "$PROPFILE"
}

stop_cron() {
  # Find cronjob PID using `pgrep`
  cronkill=$(busybox pgrep -f "crond -c ${box_run}")
  for cron in ${cronkill[@]}; do
    # kill cronjob
    kill -15 "${cron}"
  done
}

force_stop() {
  # try forcing it to shut down.
  log Warning "try forcing it to shut down."
  for bin in "${bin_list[@]}"; do
    # Use `busybox pkill` to kill the binary with signal 9, otherwise use `killall`.
    if busybox pkill -9 "${bin}"; then
      : # Do nothing if busybox pkill is successful
    else
      if command -v killall >/dev/null 2>&1; then
        killall -9 "${bin}" >/dev/null 2>&1 || true
      else
        pkill -9 "${bin}" >/dev/null 2>&1 || true
      fi
    fi
  done
  sleep 0.5
  if ! busybox pidof "${bin_name}" >/dev/null 2>&1; then
    log Warning "done, YOU can sleep peacefully."
    rm -f "${box_pid}"
  fi
}

# Check whether busybox is installed or not on the system using command -v
if ! command -v busybox &> /dev/null; then
  log Error "$(which busybox) command not found."
  exit 1
fi

if command -v ksud &>/dev/null; then
 $scripts_dir/box.tool webroot >/dev/null 2>&1
fi

case "$1" in
  start)
    stop_box >> /dev/null 2>&1
    start_box
    ;;
  stop)
    stop_box
    ;;
  restart)
    "${scripts_dir}/box.iptables" disable && stop_box
    sleep 0.5
    start_box && "${scripts_dir}/box.iptables" renew
    ;;
  status)
    # Check whether the service is running or not
    if busybox pidof "${bin_name}" >/dev/null; then
      case "${bin_name}" in
        clash) echo "${yellow}$("${bin_path}" -v)${normal}";;
        *) echo "${yellow}$("${bin_path}" version)${normal}";;
      esac
      box_bin_status
    else
      log Warning "${bin_name} shutting down, service is stopped."
    fi
    ;;
  cron)
    run_crontab="true"
    stop_cron
    sleep 0.5
    box_run_crontab
    ;;
  kcron)
    stop_cron
    ;;
  *)
    echo "${red}$0 $1 no found${normal}"
    echo "${yellow}usage${normal}: ${green}$0${normal} {${yellow}start|stop|restart|status|cron|kcron${normal}}"
    ;;
esac
